package io.wongxd.solution.util

import android.content.ActivityNotFoundException
import android.content.ContentResolver
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.provider.OpenableColumns
import androidx.annotation.RequiresApi
import java.io.BufferedOutputStream
import java.io.InputStream
import java.io.OutputStream


//   <!-- 需要访问其他应用创建的图片时申请 -->
//  <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
//
//  <!-- 需要访问其他应用创建的视频时申请 -->
//  <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
//
//  <!-- 需要访问其他应用创建的音频时申请 -->
//  <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
//
//  <!-- 旧版安卓兼容 -->
//  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
//
//  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
//                   android:maxSdkVersion="29" />

// 图片（包括照片和屏幕截图），存储在 DCIM/ 和 Pictures/ 目录中。系统将这些文件添加到 MediaStore.Images 表格中。
// 视频，存储在 DCIM/、Movies/ 和 Pictures/ 目录中。系统将这些文件添加到 MediaStore.Video 表格中。
// 音频文件，存储在 Alarms/、Audiobooks/、Music/、Notifications/、Podcasts/ 和 Ringtones/ 目录中。此外，系统还可以识别 Music/ 或 Movies/ 目录中的音频播放列表，以及 Recordings/ 目录中的录音。系统将这些文件添加到 MediaStore.Audio 表格中。Recordings/ 目录在 Android 11（API 级别 30）及更低版本中不可用。
// 下载的文件，存储在 Download/ 目录中。在搭载 Android 10（API 级别 29）及更高版本的设备上，这些文件存储在 MediaStore.Downloads 表格中。此表格在 Android 9（API 级别 28）及更低版本中不可用。

object MediaStoreHelper {

    /**
     * 写inputStream到公共目录Download
     * @param path 文件路径，必须以Download/开头，且不包含文件名
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    fun writeToDownload(
        context: Context,
        path: String,
        fileName: String,
        inputStream: InputStream
    ) {
        val contentValues = ContentValues()
        // 设置文件路径
        contentValues.put(MediaStore.Downloads.RELATIVE_PATH, path)
        // 设置文件名称
        contentValues.put(MediaStore.Downloads.DISPLAY_NAME, fileName)
        // ContentUri 表示操作哪个数据库, contentValues 表示要插入的数据内容
        val uri = context.contentResolver.insert(
            MediaStore.Downloads.EXTERNAL_CONTENT_URI,
            contentValues
        )!!
        // 向 path/filename 文件中插入数据
        val os: OutputStream = context.contentResolver.openOutputStream(uri)!!
        val bos = BufferedOutputStream(os)
        inputStream.use { istream ->
            bos.use { bos ->
                val buff = ByteArray(1024)
                var count: Int
                while (istream.read(buff).apply { count = this } != -1) {
                    bos.write(buff, 0, count)
                }
            }
        }
    }

    /**
     * 通过MediaStore获取文件uri
     * @return 获取失败返回null
     */
    @RequiresApi(Build.VERSION_CODES.Q)
    fun getFileUri(context: Context, path: String): Uri? {
        // projection代表数据库中需要检索出来的列，也可以不写，query的第二个参数传null，写了性能更好
        val projection = arrayOf(
            MediaStore.Downloads.DISPLAY_NAME,
            MediaStore.Downloads._ID,
            MediaStore.Downloads.RELATIVE_PATH
        )
        // 从path解析出路径和文件名
        val directoryPath = path.substringBeforeLast("/")
        val fileName = path.substringAfterLast("/")

        // SQL语句，路径匹配和文件名匹配
        val selection =
            "${MediaStore.Downloads.RELATIVE_PATH} LIKE ? AND ${MediaStore.Downloads.DISPLAY_NAME} = ?"
        // SQL语句参数
        val selectionArgs = arrayOf("%$directoryPath%", fileName)

        val contentResolver: ContentResolver = context.contentResolver
        val uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI
        // 使用ContentResolver查找，获得数据库指针
        val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null)

        var fileUri: Uri? = null
        if (cursor?.moveToFirst() == true) {
            val columnIndex = cursor.getColumnIndex(MediaStore.Downloads._ID)
            val fileId = cursor.getLong(columnIndex)
            fileUri = Uri.withAppendedPath(uri, fileId.toString())
            cursor.close()
        }
        return fileUri
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    fun checkFileExistence(context: Context, path: String): Boolean {
        return getFileUri(context, path) != null
    }

    fun getFileName(context: Context, uri: Uri): String {
        var fileName = ""
        val contentResolver = context.contentResolver
        // 此处只需要取出文件名这一项
        val projection = arrayOf(OpenableColumns.DISPLAY_NAME)
        contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
            val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            cursor.moveToFirst()
            fileName = cursor.getString(nameIndex)
            cursor.close()
        }

        return fileName
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    fun deleteFile(context: Context, path: String) {
        val uri = getFileUri(context, path) ?: return
        context.contentResolver.delete(uri, null, null)
    }

    @RequiresApi(Build.VERSION_CODES.Q)
    fun openFile(context: Context, path: String): Boolean {
        val intent = Intent()
        intent.action = Intent.ACTION_VIEW
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        val uri = getFileUri(context, path)
        if (uri == null) {
            return false
        }
        intent.setDataAndType(uri, context.contentResolver.getType(uri) ?: "*/*")
        try {
            context.startActivity(intent)
        } catch (exception: ActivityNotFoundException) {
            // 对于设定的MIME没有对应程序可打开的情况
            intent.setDataAndType(uri, "*/*")
            context.startActivity(intent)
        }
        return true
    }

    /** 判断是否可以使用MediaStore **/
    private fun canUseMediaStore(path: String): Boolean {
        return path.startsWith(Environment.DIRECTORY_DOWNLOADS) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
    }


}